﻿// Decompiled with JetBrains decompiler
// Type: System.Web.Razor.Tokenizer.Tokenizer`2
// Assembly: System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: 682513D6-F37E-48AC-9909-F3EE103CFF14
// Assembly location: D:\Project\Idea\无人机外网\uav\客户端工程\排查工具\bin\Release\System.Web.Razor.dll

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Resources;
using System.Web.Razor.Text;
using System.Web.Razor.Tokenizer.Symbols;

namespace System.Web.Razor.Tokenizer
{
  /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.</summary>
  /// <typeparam name="TSymbol">The type for the language symbol.</typeparam>
  /// <typeparam name="TSymbolType">The enumeration type for the language symbol.</typeparam>
  public abstract class Tokenizer<TSymbol, TSymbolType> : StateMachine<TSymbol>, ITokenizer
    where TSymbol : SymbolBase<TSymbolType>
  {
    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Initializes a new instance of the <see cref="T:System.Web.Razor.Tokenizer.Tokenizer`2" /> class.</summary>
    /// <param name="source">The source.</param>
    protected Tokenizer(ITextDocument source)
    {
      this.Source = source != null ? new TextDocumentReader(source) : throw new ArgumentNullException(nameof (source));
      this.Buffer = new StringBuilder();
      this.CurrentErrors = (IList<RazorError>) new List<RazorError>();
      this.StartSymbol();
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the source of the text document.</summary>
    /// <returns>The source of the source document.</returns>
    public TextDocumentReader Source { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets or sets the buffer for the tokenizer.</summary>
    /// <returns>The buffer for the tokenizer.</returns>
    protected StringBuilder Buffer { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets a value whether the tokenizer current location is at the end of the file.</summary>
    /// <returns>true if the tokenizer current location is at the end of the file; otherwise, false.</returns>
    protected bool EndOfFile => this.Source.Peek() == -1;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets a list of the current razor errors.</summary>
    /// <returns>A list of the current errors.</returns>
    protected IList<RazorError> CurrentErrors { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the star type for the razor comment.</summary>
    /// <returns>The star type for the razor comment.</returns>
    public abstract TSymbolType RazorCommentStarType { get; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the type of razor comment.</summary>
    /// <returns>The type of razor comment.</returns>
    public abstract TSymbolType RazorCommentType { get; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the transition type for the razor comment.</summary>
    /// <returns>The transition type for the razor comment.</returns>
    public abstract TSymbolType RazorCommentTransitionType { get; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets a value whether the tokenizer have content.</summary>
    /// <returns>true if the tokenizer have content; otherwise, false.</returns>
    protected bool HaveContent => this.Buffer.Length > 0;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the current character in the tokenizer.</summary>
    /// <returns>The current character.</returns>
    protected char CurrentCharacter
    {
      get
      {
        int num = this.Source.Peek();
        return num != -1 ? (char) num : char.MinValue;
      }
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the current source location.</summary>
    /// <returns>The current source location.</returns>
    protected SourceLocation CurrentLocation => this.Source.Location;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the current start of the source location.</summary>
    /// <returns>The current start of the source location.</returns>
    protected SourceLocation CurrentStart { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Shows the next symbol to be used.</summary>
    /// <returns>The next symbol to be used.</returns>
    public virtual TSymbol NextSymbol()
    {
      this.StartSymbol();
      return this.EndOfFile ? default (TSymbol) : this.Turn();
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Sets the tokenizer status to its initial state.</summary>
    public void Reset() => this.CurrentState = this.StartState;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Creates a language symbol type for the tokenizer with the specified content.</summary>
    /// <returns>A language symbol type for the tokenizer.</returns>
    /// <param name="start">The start of the source location.</param>
    /// <param name="content">The content value.</param>
    /// <param name="type">The symbol type.</param>
    /// <param name="errors">The razor error.</param>
    protected abstract TSymbol CreateSymbol(
      SourceLocation start,
      string content,
      TSymbolType type,
      IEnumerable<RazorError> errors);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Uses a single type of symbol.</summary>
    /// <returns>A single type of symbol.</returns>
    /// <param name="type">The type of symbol.</param>
    protected TSymbol Single(TSymbolType type)
    {
      this.TakeCurrent();
      return this.EndSymbol(type);
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Accepts the given input string into the buffer.</summary>
    /// <returns>true if the whole input string was accepted; false, if only a substring was accepted.</returns>
    /// <param name="input">The input string.</param>
    /// <param name="caseSensitive">true to indicate comparison is case sensitive; otherwise, false.</param>
    protected bool TakeString(string input, bool caseSensitive)
    {
      int num = 0;
      Func<char, char> func = (Func<char, char>) (c => c);
      if (caseSensitive)
        func = new Func<char, char>(char.ToLower);
      while (!this.EndOfFile && num < input.Length && (int) func(this.CurrentCharacter) == (int) func(input[num++]))
        this.TakeCurrent();
      return num == input.Length;
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns the start symbol used in this class.</summary>
    protected void StartSymbol()
    {
      this.Buffer.Clear();
      this.CurrentStart = this.CurrentLocation;
      this.CurrentErrors.Clear();
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns the language end symbol type used by the tokenizer.</summary>
    /// <returns>The language end symbol type.</returns>
    /// <param name="type">The enumeration type for the language symbol.</param>
    protected TSymbol EndSymbol(TSymbolType type) => this.EndSymbol(this.CurrentStart, type);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns the language end symbol type used by the tokenizer.</summary>
    /// <returns>The language end symbol type.</returns>
    /// <param name="start">The start of the source location.</param>
    /// <param name="type">The enumeration type for the language symbol.</param>
    protected TSymbol EndSymbol(SourceLocation start, TSymbolType type)
    {
      TSymbol symbol = default (TSymbol);
      if (this.HaveContent)
        symbol = this.CreateSymbol(start, this.Buffer.ToString(), type, (IEnumerable<RazorError>) this.CurrentErrors.ToArray<RazorError>());
      this.StartSymbol();
      return symbol;
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Resumes using the previous language symbol type.</summary>
    /// <param name="previous">The previous language symbol type.</param>
    protected void ResumeSymbol(TSymbol previous)
    {
      SourceLocation sourceLocation = previous.Start;
      int num = sourceLocation.AbsoluteIndex + previous.Content.Length;
      sourceLocation = this.CurrentStart;
      int absoluteIndex = sourceLocation.AbsoluteIndex;
      if (num != absoluteIndex)
        throw new InvalidOperationException(RazorResources.Tokenizer_CannotResumeSymbolUnlessIsPrevious);
      this.CurrentStart = previous.Start;
      string str = this.Buffer.ToString();
      this.Buffer.Clear();
      this.Buffer.Append(previous.Content);
      this.Buffer.Append(str);
    }

    /// <summary>Parses the source document until the condition specified by predicate is met or end file is reached.</summary>
    /// <returns>true if the predicate condition is met; false if end of file is reached.</returns>
    /// <param name="predicate">The predicate that specifies the processing condition.</param>
    protected bool TakeUntil(Func<char, bool> predicate)
    {
      while (!this.EndOfFile && !predicate(this.CurrentCharacter))
        this.TakeCurrent();
      return !this.EndOfFile;
    }

    /// <summary>Returns a function delegate, that accepts a character parameter and returns a value that indicates whether the character parameter is equal to specified character or white space.</summary>
    /// <returns>A function delegate.</returns>
    /// <param name="character">The character used to compare.</param>
    protected Func<char, bool> CharOrWhiteSpace(char character) => (Func<char, bool>) (c => (int) c == (int) character || ParserHelpers.IsWhitespace(c) || ParserHelpers.IsNewLine(c));

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Accepts the current character into the buffer.</summary>
    protected void TakeCurrent()
    {
      if (this.EndOfFile)
        return;
      this.Buffer.Append(this.CurrentCharacter);
      this.MoveNext();
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Reads to the next character from the code reader.</summary>
    protected void MoveNext() => this.Source.Read();

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Takes the string if found in the lookahead buffer into the tokenizer buffer.</summary>
    /// <returns>true if the lookahead buffer contains the expected string; otherwise, false.</returns>
    /// <param name="expected">The string to match.</param>
    /// <param name="caseSensitive">true to indicate comparison is case sensitive; otherwise, false.</param>
    protected bool TakeAll(string expected, bool caseSensitive) => this.Lookahead(expected, true, caseSensitive);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Determines whether the lookahead buffer contains the expected string.</summary>
    /// <returns>true if the lookahead buffer contains the expected string; otherwise, false.</returns>
    /// <param name="expected">The string to check.</param>
    /// <param name="caseSensitive">true to indicate comparison is case sensitive; otherwise, false.</param>
    protected bool At(string expected, bool caseSensitive) => this.Lookahead(expected, false, caseSensitive);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Reads the next symbol in the code.</summary>
    /// <returns>The next symbol to read.</returns>
    protected char Peek()
    {
      using (this.Source.BeginLookahead())
      {
        this.MoveNext();
        return this.CurrentCharacter;
      }
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns a result after the razor comment transition.</summary>
    /// <returns>The result.</returns>
    public StateMachine<TSymbol>.StateResult AfterRazorCommentTransition()
    {
      if (this.CurrentCharacter != '*')
        return this.Transition(this.StartState);
      this.TakeCurrent();
      return this.Transition(this.EndSymbol(this.RazorCommentStarType), new StateMachine<TSymbol>.State(this.RazorCommentBody));
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Parses the Razor comment body.</summary>
    /// <returns>The object that represent the state of the result.</returns>
    protected StateMachine<TSymbol>.StateResult RazorCommentBody()
    {
      this.TakeUntil((Func<char, bool>) (c => c == '*'));
      if (this.CurrentCharacter != '*')
        return this.Transition(this.EndSymbol(this.RazorCommentType), this.StartState);
      char star = this.CurrentCharacter;
      SourceLocation start = this.CurrentLocation;
      this.MoveNext();
      if (!this.EndOfFile && this.CurrentCharacter == '@')
      {
        StateMachine<TSymbol>.State newState = (StateMachine<TSymbol>.State) (() =>
        {
          this.Buffer.Append(star);
          return this.Transition(this.EndSymbol(start, this.RazorCommentStarType), (StateMachine<TSymbol>.State) (() =>
          {
            if (this.CurrentCharacter != '@')
              return this.Transition(this.StartState);
            this.TakeCurrent();
            return this.Transition(this.EndSymbol(this.RazorCommentTransitionType), this.StartState);
          }));
        });
        return this.HaveContent ? this.Transition(this.EndSymbol(this.RazorCommentType), newState) : this.Transition(newState);
      }
      this.Buffer.Append(star);
      return this.Stay();
    }

    private bool Lookahead(string expected, bool takeIfMatch, bool caseSensitive)
    {
      Func<char, char> func = (Func<char, char>) (c => c);
      if (!caseSensitive)
        func = new Func<char, char>(char.ToLowerInvariant);
      if (expected.Length == 0 || (int) func(this.CurrentCharacter) != (int) func(expected[0]))
        return false;
      string str = (string) null;
      if (takeIfMatch)
        this.Buffer.ToString();
      using (LookaheadToken lookaheadToken = this.Source.BeginLookahead())
      {
        for (int index = 0; index < expected.Length; ++index)
        {
          if ((int) func(this.CurrentCharacter) != (int) func(expected[index]))
          {
            if (takeIfMatch)
            {
              this.Buffer.Clear();
              this.Buffer.Append(str);
            }
            return false;
          }
          if (takeIfMatch)
            this.TakeCurrent();
          else
            this.MoveNext();
        }
        if (takeIfMatch)
          lookaheadToken.Accept();
      }
      return true;
    }

    [Conditional("DEBUG")]
    internal void AssertCurrent(char current)
    {
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns the next language symbol type.</summary>
    /// <returns>The next language symbol type.</returns>
    ISymbol ITokenizer.NextSymbol() => (ISymbol) this.NextSymbol();
  }
}
